package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.heima.apis.article.IArticleClient;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.tess4j.Tess4jClient;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {
    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private GreenImageScan greenImageScan;
    @Autowired
    private IArticleClient articleClient;

    /**
     * 自动审核文章
     * @param id 文章id
     */
    @Async
    @Override
    public void autoScanWmNews(Integer id) {
        // 1. 查询自媒体的文章
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews == null || StringUtils.isBlank(wmNews.getContent())){
            log.info("--------------------wmNews为空");
            return;
        }
        // 2. 从文章中提取纯文本和图片内容
        Map<String,Object> textAndImages = extractTextAndImage(wmNews);

        // 3. 审核文本
        boolean textFlag = handleTextScan((String)textAndImages.get("content"),wmNews);
        if (!textFlag){
            return;
        }
        // 4. 审核图片
        boolean imageFlag = handleImageScan((List<String>)textAndImages.get("images"),wmNews);
        if (!imageFlag){
            return;
        }
        // 5. 如果审核通过远程调用feign接口保存app端的文章
        ResponseResult responseResult = saveAppArticle(wmNews);
        // 6. 更新自媒体端的文章的状态和app端的文章id
        if (responseResult.getCode() == AppHttpCodeEnum.SUCCESS.getCode()){
            Long articleId = (Long) responseResult.getData(); // articleId
            wmNews.setArticleId(articleId);
            updateWmNews(wmNews, (short) 9,"审核通过");
        }else {
            throw new RuntimeException("APP端文章保存失败");
        }
    }

    @Autowired
    private WmUserMapper wmUserMapper;
    @Autowired
    private WmChannelMapper wmChannelMapper;
    /**
     * 远程调用feign接口保存app端的文章
     * @param wmNews
     * @return
     */
    @Override
    public ResponseResult saveAppArticle(WmNews wmNews) {
        ArticleDto dto = new ArticleDto();
        BeanUtils.copyProperties(wmNews, dto,"id");
        // 设置特殊属性
        // authorId
        dto.setAuthorId(wmNews.getUserId().longValue());
        // authorName
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        String name = wmUser.getNickname();
        dto.setAuthorName(name);
        // channelName
        WmChannel wmChannel = wmChannelMapper.selectById(wmNews.getChannelId());
        dto.setChannelName(wmChannel.getName());
        // layout
        dto.setLayout(wmNews.getType());
        // createTime
        dto.setCreatedTime(new Date());
        // 如果wmNews中的articleId不为空，证明是在修改文章
        if (wmNews.getArticleId() != null){
            dto.setId(wmNews.getArticleId());
        }
        // 远程调用
        ResponseResult responseResult = articleClient.saveArticle(dto);

        return responseResult;
    }


    @Autowired
    private FileStorageService fileStorageService;

    @Autowired
    private Tess4jClient tess4jClient;
    /**
     * 审核图片，如果审核失败还需要修改状态
     * @param images 图片路径
     * @param wmNews 文章
     * @return
     */
    private boolean handleImageScan(List<String> images, WmNews wmNews) {
        boolean flag = true;
        if (CollectionUtils.isEmpty(images)){
            return flag;
        }
        // 图片去重
        images = images.stream().distinct().collect(Collectors.toList());
        for (String imageUrl : images) {
            try {
                byte[] bytes = fileStorageService.downLoadFile(imageUrl);
                // OCR识别，将图片上的文字提取出来
                ByteArrayInputStream is = new ByteArrayInputStream(bytes);
                BufferedImage bufferedImage = ImageIO.read(is);
                String result = tess4jClient.doOCR(bufferedImage);
                // 判断是否包含自管理敏感词
                boolean sensitiveFlag  = handleSensitiveScan(result, wmNews);
                if (!sensitiveFlag){
                    return false;
                }
                // 调用阿里云的图片检测
                Map map = greenImageScan.imageScan(bytes);
                String suggestion = (String) map.get("suggestion");
                String reason = "审核不通过,原因:"+(String) map.get("labels");
                if ("block".equals(suggestion)){
                    // 审核不通过
                    flag = false;
                    // 修改文章状态和失败原因
                    updateWmNews(wmNews, (short) 2,reason);
                    return flag;
                }
                if ("review".equals(suggestion)){
                    // 人工审核
                    flag = false;
                    // 修改文章状态和失败原因
                    updateWmNews(wmNews, (short) 3,reason);
                    return flag;
                }

            } catch (Exception e) {
                e.printStackTrace();
                flag = false;
            }
        }
        return flag;
    }

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;
    /**
     * 审核文本，如果审核失败还需要修改文章状态
     * @param content 文本内容
     * @param wmNews 文章
     * @return
     */
    private boolean handleTextScan(String content, WmNews wmNews) {
        boolean flag = true;
        if (StringUtils.isBlank(content)){
            return flag;
        }
        // 调用自管理敏感词检测方法
        boolean sensitiveFlag = handleSensitiveScan(content, wmNews);
        if (!sensitiveFlag){
            return false;
        }
        // 调用阿里云的审核接口
        try {
            Map map = greenTextScan.greenTextScan(content);
            String suggestion = (String) map.get("suggestion");
            String labels = (String) map.get("labels");
            if ("block".equals(suggestion)){
                // 审核不通过
                flag = false;
                // 修改文章状态
                updateWmNews(wmNews,(short)2,labels);
            }
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
        }
        return flag;
    }

    /**
     * 判断文本内容中是否包含自管理敏感词
     * @param result
     * @param wmNews
     * @return
     */
    public boolean handleSensitiveScan(String result,WmNews wmNews){
        boolean flag = true;
        // 自管理敏感词审核
        // 查询数据库中的所有敏感词
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(null);
        List<String> sensitives = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
        // 初始化敏感词库
        SensitiveWordUtil.initMap(sensitives);
        // 判断是否包含敏感词
        Map<String, Integer> sensitiveMap = SensitiveWordUtil.matchWords(result);
        if (sensitiveMap.size() > 0){
            // 包含自管理敏感词
            updateWmNews(wmNews,(short)2,"文章中包含违规内容"+sensitiveMap);
            flag = false;
        }

        return flag;
    }

    /**
     * 修改文章状态的方法
     * @param wmNews 文章对象
     * @param status 状态
     * @param reason 审核失败原因
     */
    private void updateWmNews(WmNews wmNews, short status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 提取文章中的纯文本和图片内容
     * @param wmNews 原始文章
     * @return
     */
    private Map<String, Object> extractTextAndImage(WmNews wmNews) {
        // 用于封装纯文本数据
        StringBuilder stringBuilder = new StringBuilder(wmNews.getTitle()+","+wmNews.getLabels()+",");
        // 用于封装图片数据
        List<String> images = new ArrayList<>();
        // 从内容中提取文本和图片
        String jsonString = wmNews.getContent();
        List<Map> maps = JSONArray.parseArray(jsonString, Map.class);
        for (Map map : maps) {
            if ("text".equals(map.get("type"))){
                // 是文本内容
                stringBuilder.append( map.get("value")+",");
            }

            if ("image".equals(map.get("type"))){
                // 是图片
                images.add((String) map.get("value"));
            }
        }
        // 处理封面图片
        String imagesStr = wmNews.getImages();
        if (StringUtils.isNotBlank(imagesStr)){
            List<String> coverImages = Arrays.asList(imagesStr.split(","));
            images.addAll(coverImages);
        }


        // 封装并返回数据
        Map map = new HashMap();
        map.put("content",stringBuilder.toString());
        map.put("images",images);
        return map;
    }
}
